import React, { useCallback, useContext, useRef, useState } from 'react';
import {
  Icon,
  Tooltip,
  Input,
  Select,
  Menu,
  Dropdown,
  message,
  Popconfirm,
  Badge,
  Row,
} from 'antd';
import PropTypes from 'prop-types';
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import classnames from 'classnames';
// eslint-disable-next-line import/no-named-default
import { connect } from 'dva';
import { default as TransformerContext } from '@/pages/Transformer/context';
// eslint-disable-next-line import/no-named-default
import { default as TargetContext } from '@/pages/Transformer/components/TargetPanel/targetContext';
import Context from '../context';
import { SCHEMA_TYPE, STRING_TYPE, ARRAY_TYPE, OBJECT_TYPE, ANY_TYPE } from '../settings';
import { hasChildren } from '@/utils/utils';
import styles from '../styles.less';

const { Option } = Select;

const timestamp = +new Date();

// 时间戳大的 优先级高，表示是当前操作的模式（全局or本地 toggle）
function isShow(global, local) {
  const { timestamp: lt, status: ls } = local;

  if (typeof get(global, 'timestamp') !== 'number') {
    return ls;
  }
  const { timestamp: gt, status: gs } = global;

  return gt > lt ? gs : ls;
}

function getInputWidth(windowWidth) {
  return (windowWidth - 3 * 8) / 2 - 16 * 2 - 30 - 24 - 90 - 8 * 4 - 13 - 14 - 126;
}

function Node({ parent, nodePath, current, offset, children, windowWidth, handleSelect }) {
  const { state = {}, dispatch } = useContext(Context);

  const { state: Tstate = {}, dispatch: Tdispatch } = useContext(TransformerContext);

  const { state: TargetState = {}, dispatch: Targetdispatch } = useContext(TargetContext);

  const isRoot = nodePath === '';

  const parentNodeType = get(parent, 'nodeType');

  const isArrayItem = parentNodeType === ARRAY_TYPE;

  const [width] = useState(getInputWidth(windowWidth));

  // 根节点默认展开
  const [localToggle, setLocalToggle] = useState(() => ({
    timestamp,
    status: isRoot,
  }));

  const prefix = isRoot ? '' : `${nodePath}.`;

  // 适用于除`rules`外的节点普通属性，
  const changeNodeNormalAttr = useCallback(
    (value, path, attrName) => {
      dispatch({
        type: 'update_node_normal_attr',
        payload: {
          value,
          path,
          attrName,
        },
      });
    },
    [dispatch]
  );

  const addSibingNode = useCallback(
    (parent, current, nodePath) => {
      dispatch({
        type: 'add_sibling_node',
        payload: {
          parent,
          current,
          nodePath,
        },
      });
    },
    [dispatch]
  );

  const addChildNode = useCallback(
    (parent, current, nodePath) => {
      dispatch({
        type: 'add_child_node',
        payload: {
          parent,
          current,
          nodePath,
        },
      });
    },
    [dispatch]
  );

  const deleteCurrentNode = useCallback(
    nodePath => {
      dispatch({
        type: 'delete_current_node',
        payload: {
          nodePath,
        },
      });
    },
    [dispatch]
  );

  // const copyCurrentNode = useCallback(
  //   (parent, current, nodePath) => {
  //     dispatch({
  //       type: 'copy_current_node',
  //       payload: {
  //         parent,
  //         current,
  //         nodePath,
  //       },
  //     });
  //   },
  //   [dispatch]
  // );

  // 根节点的parent预期是undefined
  function renderPlus(parent, current, nodePath) {
    const { nodeType } = current;

    const parentNodeType = get(parent, 'nodeType');

    const isRoot = parent === undefined;

    const isObjectRoot = isRoot && nodeType === OBJECT_TYPE;

    // ## 只添加子节点
    // 1、根节点是object
    // 2、当前是object且父节点是array
    // 3、当前是array但还没有children
    const onlyChild =
      isObjectRoot ||
      (parentNodeType === ARRAY_TYPE && nodeType === OBJECT_TYPE) ||
      (nodeType === ARRAY_TYPE && !hasChildren(current));

    // ## 只有兄弟节点
    // 1、父节点不是array的普通节点(指除除object、boolean和array外)
    // 2、父节点是object且自身不是object的
    const onlySibling =
      (SCHEMA_TYPE.filter(k => k !== ARRAY_TYPE).includes(parentNodeType) &&
        ![OBJECT_TYPE, ARRAY_TYPE].includes(nodeType)) ||
      (parentNodeType === OBJECT_TYPE && nodeType !== OBJECT_TYPE);

    //
    const childAndSibling = nodeType === OBJECT_TYPE && !isRoot;

    if (onlyChild) {
      return (
        <Tooltip placement="top" title="子节点">
          <Icon
            type="plus"
            className={classnames(styles.action, styles.add)}
            onClick={() => {
              addChildNode(parent, current, nodePath);

              // 保证子节点添加完可见，避免添加时父节点是`收起`状态
              if (localToggle.status === false) {
                setLocalToggle({
                  timestamp: +new Date(),
                  status: true,
                });
              }
            }}
          />
        </Tooltip>
      );
    }

    if (onlySibling) {
      return (
        <Tooltip placement="top" title="兄弟节点">
          <Icon
            type="plus"
            className={classnames(styles.action, styles.add)}
            onClick={() => addSibingNode(parent, current, nodePath)}
          />
        </Tooltip>
      );
    }

    // 父节点是array时, 子节点
    if (childAndSibling) {
      return (
        <Dropdown
          overlay={
            <Menu>
              <Menu.Item>
                <span onClick={() => addSibingNode(parent, current, nodePath)}>兄弟节点</span>
              </Menu.Item>
              <Menu.Item>
                <span
                  onClick={() => {
                    addChildNode(parent, current, nodePath);

                    // 保证子节点添加完可见，避免添加时父节点是`收起`状态
                    if (localToggle.status === false) {
                      setLocalToggle({
                        timestamp: +new Date(),
                        status: true,
                      });
                    }
                  }}
                >
                  子节点
                </span>
              </Menu.Item>
            </Menu>
          }
        >
          <Icon type="plus" className={classnames(styles.action, styles.add)} />
        </Dropdown>
      );
    }

    return null;
  }

  // open是内部状态
  const show = isShow(state.globalToggle, localToggle);

  const inputRef = useRef(null);

  // 快速映射
  const dotted =
    Array.isArray(get(current, 'nodePath')) &&
    isEqual(get(current, 'nodePath'), get(Tstate, 'sourceNodePath'));

  return (
    <span
      style={{ display: 'inline-flex', alignItems: 'center' }}
      onDoubleClick={e => {
        e.stopPropagation();
      }}
      onClick={e => e.stopPropagation()}
    >
      {/* 防止Drawer双击 冒泡到 <Expandable />组件 */}
      {/* 属性名称 */}
      <i
        className={classnames(
          'tgIcon',
          `icon-${current.nodeType}`.toLocaleLowerCase(),
          styles.icon,
          styles[`${current.nodeType}`.toLocaleLowerCase()]
        )}
      />

      <Input
        ref={inputRef}
        onClick={e => {
          e.stopPropagation();
          inputRef.current.select();
        }}
        onContextMenu={e => e.preventDefault()}
        defaultValue={get(current, 'nodeName')}
        onBlur={e => {
          if (e.target.value === current.nodeName) {
            return;
          }

          if (!e.target.value) {
            message.error('key不能为空');
          } else if (
            Array.isArray(parent.children) &&
            parent.children.some(k => k.nodeName === e.target.value)
          ) {
            message.error('当前key重复了');
          } else {
            dispatch({
              type: 'modify_node_name',
              payload: {
                node: current,
                nodePath,
                newName: e.target.value,
              },
            });
          }
        }}
        className={styles.nodeName}
        disabled={isRoot || isArrayItem}
        style={{
          width: width - offset,
        }}
      />

      {/* 值类型 */}
      <Select
        value={get(current, `nodeType`) || ANY_TYPE}
        placeholder="未知"
        onChange={value => {
          changeNodeNormalAttr(value, `${prefix}nodeType`, 'nodeType');
          // 因为array和object时，会自动最近一个默认子节点
          if ([OBJECT_TYPE, ARRAY_TYPE].includes(value)) {
            setLocalToggle({
              timestamp: +new Date(),
              status: true,
            });
          }
        }}
      >
        {SCHEMA_TYPE.map(item => {
          return (
            <Option value={item} key={item}>
              {item}
            </Option>
          );
        })}
      </Select>

      <Tooltip placement="top" title="删除">
        {hasChildren(current) ? (
          <Popconfirm
            title="注意，所有子节点都会被删除！"
            onConfirm={() => deleteCurrentNode(nodePath)}
          >
            <Icon type="delete" className={classnames(styles.action, styles.delete)} />
          </Popconfirm>
        ) : (
          <Icon
            type="delete"
            className={classnames(styles.action, styles.delete)}
            onClick={() => deleteCurrentNode(nodePath)}
          />
        )}
      </Tooltip>

      {renderPlus(parent, current, nodePath)}

      <Tooltip placement="top" title="快速映射">
        <Badge dot={dotted}>
          <Icon
            type="share-alt"
            className={classnames(styles.action, styles.link)}
            style={{ marginRight: 4 }}
            onClick={handleSelect}
          />
        </Badge>
      </Tooltip>

      {/* {parentNodeType !== ARRAY_TYPE && !isRoot && (
        <Tooltip placement="top" title="复制节点">
          <Icon
            type="copy"
            className={classnames(styles.action, styles.copy)}
            onClick={() => copyCurrentNode(parent, current, nodePath)}
          />
        </Tooltip>
      )} */}

      {show && children}
    </span>
  );
}

const NODE_TYPE = {
  nodeTitle: PropTypes.string,
  nodeName: PropTypes.string,
  nodeType: PropTypes.oneOf(SCHEMA_TYPE),
  children: PropTypes.array,
};

Node.propTypes = {
  parent: PropTypes.shape(NODE_TYPE),
  nodePath: PropTypes.string.isRequired,
  current: PropTypes.shape(NODE_TYPE).isRequired,
};

Node.defaultProps = {
  parent: undefined,
};

export default connect(({ setting }) => ({
  windowWidth: setting.size.width,
}))(Node);
